package cn.harry.config;

import cn.harry.component.security.filter.JwtAuthenticationTokenFilter;
import cn.harry.component.security.handle.RestAuthenticationEntryPoint;
import cn.harry.component.security.handle.RestfulAccessDeniedHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.annotation.Resource;

/**
 * SpringSecurity的配置
 *
 * @author honghh Date 2019/10/08 10:47 Copyright (C) www.tech-harry.cn
 */
@Slf4j
@Configuration
@EnableWebSecurity
public class SecurityConfiguration {

	/**
	 * 自定义用户认证逻辑
	 */
	@Resource
	private UserDetailsService userDetailsService;

	@Resource
	private RestfulAccessDeniedHandler restfulAccessDeniedHandler;

	@Resource
	private RestAuthenticationEntryPoint restAuthenticationEntryPoint;

	@Bean
	protected SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
				// 由于使用的是JWT，我们这里不需要csrf
				.csrf(AbstractHttpConfigurer::disable)
				// 基于token，所以不需要session
				.sessionManagement(AbstractHttpConfigurer::disable)

				.authorizeRequests(author -> author
						// 允许对于网站静态资源的无授权访问
						.antMatchers(HttpMethod.GET,
								"/webjars/**",
								"/doc.html",
								"/swagger-resources/**",
								"/v3/api-docs/**",
								"/swagger-ui/**",
								"/swagger-ui.html")
						.permitAll()

						// 允许匿名访问
						.antMatchers("/admin/**").permitAll()

						.anyRequest().authenticated());

		// 禁用缓存
		http.headers().cacheControl();
		// 添加JWT filter
		http.addFilterBefore(jwtAuthenticationTokenFilter(),
				UsernamePasswordAuthenticationFilter.class);

		// 添加自定义未授权和未登录结果返回
		http.exceptionHandling().accessDeniedHandler(restfulAccessDeniedHandler)
				.authenticationEntryPoint(restAuthenticationEntryPoint);

		// 注入authenticationManager
		http.authenticationManager(authenticationManager(http));

		return http.build();
	}

	/**
	 * 身份认证接口 构造一个AuthenticationManager，使用自定义的userDetailsService和passwordEncoder
	 */
	@Bean
	public AuthenticationManager authenticationManager(HttpSecurity httpSecurity)
			throws Exception {
		return httpSecurity.getSharedObject(AuthenticationManagerBuilder.class)
				.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder())
				.and().build();
	}

	/**
	 * 强散列哈希加密实现
	 */
	@Bean
	public PasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
	}

	@Bean
	public JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter() {
		return new JwtAuthenticationTokenFilter();
	}

}
